package com.dsunsoft.rtu.core.config;

import com.dsunsoft.rtu.common.entity.RestCode;
import com.dsunsoft.rtu.common.entity.RestResult;
import com.dsunsoft.rtu.common.exception.BaseException;
import com.dsunsoft.rtu.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 统一异常处理
 *
 * @author ygm
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义业务错误
     */
    @ExceptionHandler(BaseException.class)
    public Map<String, Object> baseException(HttpServletRequest request, BaseException e) {
        log.error("业务错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        Object errorMessage;
        int code = e.getCode();
        if (e instanceof BizException) {
            BizException bizEx = (BizException) e;
            errorMessage = bizEx.getMessage();
        } else {
            errorMessage = e.getMessage();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        map.put("data", null);
        map.put("message", errorMessage);
        return map;
    }

    /**
     * 数据验证错误 @Validated
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestResult<String> methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        log.error("参数验证错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String errorMessage = fieldErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
        return new RestResult<>(RestCode.PARAM_IS_ERROR, null, errorMessage);
    }

    /**
     * 参数类型错误
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public RestResult<String> methodArgumentTypeMismatchException(HttpServletRequest request, MethodArgumentTypeMismatchException e) {
        log.error("参数类型错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        return new RestResult<>(RestCode.PARAM_TYPE_ERROR);
    }

    /**
     * 请求方法错误
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public RestResult<String> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
        log.error("请求方法错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        return new RestResult<>(RestCode.REQUEST_METHOD_ERROR);
    }

    /**
     * 参数读取错误
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public RestResult<String> httpMessageNotReadableException(HttpServletRequest request, HttpMessageNotReadableException e) {
        log.error("参数读取错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        return new RestResult<>(RestCode.PARAM_NOT_COMPLETE);
    }

    /**
     * 404
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public RestResult<String> noHandlerFoundException(HttpServletRequest request, NoHandlerFoundException e) {
        log.error("请求地址错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        return new RestResult<>(RestCode.NOT_FOUND);
    }

    /**
     * 捕捉其他所有异常
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public RestResult<String> otherException(HttpServletRequest request, Throwable e) {
        log.error("系统错误 [" + request.getMethod() + " " + request.getRequestURL() + "], 详细: ", e);
        return new RestResult<>(RestCode.ERROR);
    }
}
